home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Information / Mac Programming Secrets 1.0.1 / Chapter 10 / Command Period.c < prev    next >
C/C++ Source or Header  |  1992-05-19  |  9KB  |  272 lines

  1. #include "Command Period.h"
  2. #include "Standard Stuff.h"
  3. #include "Script.h"
  4. #include "Processes.h"
  5. #include "GestaltEqu.h"
  6.  
  7.  
  8. /*******************************************************************************
  9.  
  10.     TestCommandPeriod
  11.  
  12.     Simple test routine for our command-period checker. It creates a dialog
  13.     and displays its contents with DrawDialog (as opposed to calling
  14.     ModalDialog to handle the update event). We then go into a tight loop that
  15.     exits only when there is a command-period in the event queue.
  16.  
  17. *******************************************************************************/
  18. void TestCommandPeriod()
  19. {
  20.     DialogPtr    dlg;
  21.  
  22.     dlg = GetNewDialog(256, nil, (WindowPtr) -1);
  23.     DrawDialog(dlg);
  24.     while (!AbortInQueue()) ;
  25.  
  26.     DisposeDialog(dlg);
  27. }
  28.  
  29.  
  30. /*******************************************************************************
  31.  
  32.     Variables for the Command-period checker.
  33.  
  34. *******************************************************************************/
  35.  
  36. #define    kModifiersMask        0xFF00 & ~cmdKey    /*    We need all modifiers
  37.                                                     except the command key
  38.                                                     for KeyTrans. */
  39. #define    kOtherCharCodeMask    0x00FF0000            /*    Get the key out of the
  40.                                                     ASCII1 byte. */
  41. static const char    kPeriod    = '.';
  42.  
  43.  
  44. /*******************************************************************************
  45.  
  46.     Call an A/UX service routine.
  47.  
  48. *******************************************************************************/
  49.  
  50. pascal long AUXDispatch(short select, void* arg)
  51.     = 0xABF9;
  52.  
  53.  
  54. /*******************************************************************************
  55.  
  56.     AbortInQueue
  57.  
  58.     Looks for a Command-Period in the event queue. If we are running under the
  59.     Mac OS, we find the head of the queue and walk the elements, looking for a
  60.     keyDown event. This won’t work under A/UX, which doesn’t maintain a normal
  61.     Mac OS event queue. When running under A/UX, we make a special call,
  62.     asking A/UX to look through its private structures for a specific event
  63.     for us.
  64.  
  65.     Note that this routine returns FALSE if we are running in the background.
  66.     This is because we don’t want to stop whatever we’re doing if the user
  67.     presses Command-period for the foreground application.
  68.  
  69. *******************************************************************************/
  70. Boolean    AbortInQueue()
  71. {
  72.     const short AUX_FIND_EVENT = 8;
  73.  
  74.     EvQElPtr    queueEntryPtr;
  75.     Boolean        result;
  76.     struct {
  77.         EventRecord        mask;
  78.         EventRecord        value;
  79.     } eventFilter;
  80.  
  81.     result = FALSE;
  82.     if (IsFrontProcess()) {
  83.         if (IsRunningUnderAUX()) {
  84.  
  85.             // To get A/UX to look for a certain event, we fill out a
  86.             // specification and a mask. This is in the form of two
  87.             // EventRecords. The first one contains the values we want
  88.             // to look for. The second specifies the fields we want to
  89.             // search.
  90.  
  91.             eventFilter.value.what = keyDown;        // Find a keyDown event
  92.             eventFilter.value.message = kPeriod;    // key = '.'
  93.             eventFilter.value.modifiers = cmdKey;    // with command key
  94.  
  95.             eventFilter.mask.what = everyEvent;
  96.             eventFilter.mask.message = charCodeMask;
  97.             eventFilter.mask.modifiers = cmdKey;
  98.             eventFilter.mask.when = 0;
  99.             SetPt(&eventFilter.mask.where, 0, 0);
  100.  
  101.             // We return that there is a command-period on the queue
  102.             // if AUXDispatch returns a positive value AND
  103.             // it returns a non-nullEvent in eventFilter.
  104.  
  105.             result = (AUXDispatch(AUX_FIND_EVENT, &eventFilter) > 0) &&
  106.                         (eventFilter.value.what != nullEvent);
  107.         } else {
  108.  
  109.             // Running under Mac OS, so walk the queue. The head is in
  110.             // the low-memory location returned by GetEvQHdr, and
  111.             // follows the normal OS queue conventions. For each entry
  112.             // in the queue, call “CmdPeriod” to test it.
  113.  
  114.             result = FALSE;
  115.             queueEntryPtr = (EvQElPtr) GetEvQHdr()->qHead;
  116.             while (!result && (queueEntryPtr != nil)) {
  117.                 result = CmdPeriod((EventPtr) &queueEntryPtr->evtQWhat);
  118.                 if (!result) {
  119.                     queueEntryPtr = (EvQElPtr) queueEntryPtr->qLink;
  120.                 }
  121.             }    /* Scanning queue */
  122.         }    /* Running under Mac OS */
  123.     }    /* If front process */
  124.     return result;
  125. }
  126.  
  127.  
  128. /*******************************************************************************
  129.  
  130.     CmdPeriod
  131.  
  132.     Radical cool way to see if the event record represents a Command-.
  133.     keepers. Normally, you might wonder: “What’s the problem? All you have to
  134.     do is check the modifiers field to see if the command-key is down, and
  135.     check the message field to see what key was pressed.” Well, the problem is
  136.     that under some systems, holding down the Command key negates any effect
  137.     the Shift key has. This means that on systems where the period is a
  138.     shifted character, when you hold down the Command key, you won’t be able
  139.     to press period.
  140.  
  141.     The way to fix this is to rerun the sequence of events involved in mapping
  142.     a key code into an ASCII value, except that this time we don’t factor the
  143.     Command key into the equation.
  144.  
  145.     The event record has everything we need. It has the modifier keys that
  146.     were pressed at the time of the event, and it has the key code. What we do
  147.     is take the modifiers, clear the bit that says the Command key was
  148.     pressed, and pass the modified modifiers and the key code to KeyTrans.
  149.     After that, we’ll be able to examine the resulting ASCII value on its own
  150.     merits.
  151.  
  152.     From Harvey’s Technote #263: International Canceling
  153.  
  154. *******************************************************************************/
  155. Boolean CmdPeriod( EventPtr theEvent )
  156. {
  157.     Boolean  result;
  158.     short    keyCode;
  159.     long     virtualKey, keyInfo, lowChar, highChar, state, keyCID;
  160.     Handle   hKCHR;
  161.  
  162.     result = false;
  163.  
  164.     if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
  165.  
  166.         // See if the command key is down.  If it is, find out the ASCII
  167.         // equivalent for the accompanying key.
  168.  
  169.         if ((theEvent->modifiers & cmdKey) != 0 ) {
  170.  
  171.             virtualKey = (theEvent->message & keyCodeMask) >> 8;
  172.  
  173.             // Mask out the command key and merge in the virtualKey
  174.             keyCode    = (theEvent->modifiers & kModifiersMask) | virtualKey;
  175.             state    = 0;
  176.  
  177.             keyCID    = GetScript(GetEnvirons(smKeyScript), smScriptKeys);
  178.             hKCHR    = GetResource('KCHR', keyCID);
  179.  
  180.             if (hKCHR != nil) {
  181.                 keyInfo = KeyTrans(*hKCHR, keyCode, &state);
  182.                 ReleaseResource( hKCHR );
  183.             } else {
  184.                 keyInfo = theEvent->message;
  185.             }
  186.  
  187.             lowChar =  keyInfo & charCodeMask;
  188.             highChar = (keyInfo & kOtherCharCodeMask) >> 16;
  189.             if ((lowChar == kPeriod) || (highChar == kPeriod))
  190.                 result = true;
  191.  
  192.         }  // end the command key is down
  193.     }  // end key down event
  194.  
  195.     return result;
  196. }
  197.  
  198.  
  199. /*******************************************************************************
  200.  
  201.     IsFrontProcess
  202.  
  203.     System 6.0 and 7.0 groovy routine that checks to see if we are the
  204.     foreground (foregone?) process. Under System 6.0, we rely on keeping track
  205.     of Suspend and Resume events in our main event loop. Under 7.0, we can
  206.     just ask the Process Manager.
  207.  
  208.     Note that gInBackground is maintained externally, usually by your main
  209.     event loop.
  210.  
  211. *******************************************************************************/
  212. Boolean IsFrontProcess()
  213. {
  214.     Boolean                    result;
  215.     Boolean                    hasProcessMgr;
  216.     OSErr                    err;
  217.     ProcessSerialNumber        aPSN;
  218.     ProcessSerialNumber        currentPSN = {0, kCurrentProcess};
  219.  
  220.     if (HasGestaltAttr(gestaltOSAttr, gestaltLaunchControl)) {
  221.         err = GetFrontProcess(&aPSN);
  222.         err = SameProcess(&aPSN, ¤tPSN, &result);
  223.         return result;
  224.     } else {
  225.         return !gInBackground;
  226.     }
  227. }
  228.  
  229.  
  230. /*******************************************************************************
  231.  
  232.     IsRunningUnderAUX
  233.  
  234.     See if we are running under A/UX. We make this check in two ways. First,
  235.     we call Gestalt to see what it says. If it knows about A/UX, we see if the
  236.     version that was returned is non-zero (indicating that A/UX is running) or
  237.     not. If Gestalt doesn’t recognize the A/SUX selector, then we check by
  238.     hand by looking into low-memory. Bit 9 of HWCfgFlags is set if A/UX is
  239.     running.
  240.  
  241. *******************************************************************************/
  242. Boolean IsRunningUnderAUX()
  243. {
  244.     OSErr    err;
  245.     long    response;
  246.     #define HWCfgFlags 0x0B22
  247.  
  248.     err = Gestalt(gestaltAUXVersion, &response);
  249.     if (err == noErr) {
  250.         return response != 0;
  251.     } else {
  252.         // return TRUE if bit 9 of HWCfgFlags is set.
  253.         return ((*(short *) HWCfgFlags) & (1 << 9)) != 0;
  254.     }
  255. }
  256.  
  257.  
  258. /*******************************************************************************
  259.  
  260.     HasGestaltAttr
  261.  
  262.     Handy utility to see if the specified bit in the result of the specified
  263.     Gestalt selector is set or not.
  264.  
  265. *******************************************************************************/
  266. Boolean HasGestaltAttr(OSType itsAttr, short itsBit)
  267. {
  268.     long response;
  269.     return (Gestalt(itsAttr, &response) == noErr) && (((response >> itsBit) & 1) != 0);
  270. }
  271.  
  272.